#pragma once
#include <list>
#include <condition_variable>
#include <sys/epoll.h>
#include <functional>
#include <thread>
#include <unordered_map>
#include <memory>
#include <semaphore.h>
#include <iostream>
#include <string>
#include <vector>

const static int default_events_num = 1024;

class thread_handle
{
private:
    void setnoblocking(int fd)
    {
        int flags = fcntl(fd, F_GETFL, 0);
        fcntl(fd, F_SETFL, flags | O_NONBLOCK);
    }

    void thread_task()
    {
        while (true)
        {
            int ret = epoll_wait(_epfd, _events, default_events_num, -1);
            if (ret < 0)
            {
                std::cout << "epoll_wait error!" << std::endl;
                break;
            }
            if (ret == 0)
                continue;
            for (int i = 0; i < ret; i++)
            {
                int sockfd = _events[i].data.fd;
                std::string msg;
                if (_events[i].events & EPOLLIN)
                {
                    while (true)
                    {
                        char buffer[1024] = {0};
                        int n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
                        if (n == 0)
                        {
                            std::cout << sockfd << "号客户端断开连接!" << std::endl;
                            epoll_ctl(_epfd, EPOLL_CTL_DEL, sockfd, nullptr);
                            close(sockfd);
                        }
                        else if (n > 0)
                        {
                            buffer[n] = 0;
                            msg += buffer;
                        }
                        else
                        {
                            if (errno == EAGAIN)
                                break;
                            else if (errno == EINTR)
                                continue;
                        }
                    }
                    std::cout << "接收到" << sockfd << "号客户端消息: " << msg << std::endl;
                }
                if (_events[i].events & EPOLLOUT)
                {
                    while (true)
                    {
                        int n = send(_events[i].data.fd, msg.c_str(), msg.size(), 0);
                        if (n > 0)
                        {
                            if (n == msg.size())
                                continue;
                            else if (n < msg.size())
                                break;
                        }
                        else
                        {
                            if (errno == EAGAIN)
                                break;
                            else if (errno == EINTR)
                                continue;
                        }
                    }
                }
            }
        }
    }

public:
    thread_handle()
        : _events(new epoll_event[default_events_num])
    {
        sem_init(&sem_queue, 0, 1);
        sem_init(&sem_thread, 0, 0);
        _epfd = epoll_create(128);
        std::thread t(std::bind(&thread_handle::thread_task, this));
        t.detach(); // 自己运行完就不管了呗
    }

    void thread_start()
    {
    }

    ~thread_handle()
    {
        delete[] _events;
        sem_destroy(&sem_queue);
        sem_destroy(&sem_thread);
    }

    void push(int fd)
    {
        setnoblocking(fd);
        epoll_event ev;
        ev.data.fd = fd;
        ev.events = EPOLLIN | EPOLLOUT | EPOLLET;
        epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &ev);
        std::cout << "[新线程]:获得一个新的连接: " << fd << std::endl;
    }

protected:
    std::list<int> _queue; // 存储连接套接字
    epoll_event *_events;
    sem_t sem_queue;
    sem_t sem_thread;
    int _epfd;
};

typedef std::shared_ptr<thread_handle> thread_ptr;
const static int default_threads_num = 1;
// 对所有线程进行一个管理
class thread_handle_manager
{
private:
    int get_thread_id()
    {
        return rand() % default_threads_num;
    }

public:
    thread_handle_manager()
    {
        for (int i = 0; i < default_threads_num; i++) // 预先开10个线程
        {
            thread_ptr tp(new thread_handle);
            _threads.insert(std::make_pair(i, tp));
        }
    }

    void push_sockfd(int fd)
    {
        int num = get_thread_id();
        _threads[num]->push(fd);
        std::cout << "向" << num << "号线程插入任务！" << std::endl;
    }

protected:
    std::unordered_map<int, thread_ptr> _threads;
};